/**
 * @author:albert
 * @date:2016年6月4日
 */
package com.bkbw.live.common.math;

/**
 * @author albert
 *
 */
public class CircleSector {
	float x;
	float z;
	float radius;
	float radiusSqr;
	float dirx;
	float dirz;
	float theta;
	float cosTheta;
	
	/*
	 * x 扇形圆心的x 
	 * z 扇形圆心的z
	 * radius 扇形半径
	 * dirx 扇形朝向向量的x分量
	 * dirz 扇形朝向向量的z分量
	 * theta 扇形朝向向量和两边的夹角
	 */
	public CircleSector(float x, float z, float radius, float dirx, float dirz, float theta) {
		this.x = x;
		this.z = z;
		this.radius = radius;
		radiusSqr = radius * radius;
		float dirlen = (float)Math.sqrt(dirx * dirx + dirz * dirz);
		this.dirx = dirx / dirlen;
		this.dirz = dirz / dirlen;
		this.theta = theta;
		cosTheta = (float)Math.cos(theta);
	}
	
	public boolean isPointInSector(float x, float z) {
		// 计算扇形和点的交叉有两步
		// 1 计算点到扇形所在圆圆心的距离，若大于扇形半径，则点肯定不在扇形内
		// 2 若点到圆心距离小于半径，则计算点到圆心的线段要在扇形两条边之间，p表示点，c表示扇形圆心，
		// 也就是p-c这个向量和扇形的方向向量的夹角a要小于等于扇形的theta, a <= theta, 因为cos是降调函数，所以cos(a) > cos(theta)
		// cos(a) = ((p - c) dot dir) / |p - c| > cos(theta)
		
		float dx = x - this.x;
		float dz = z - this.z;
		float sqrLen = dx * dx + dz * dz;
		if (sqrLen > radiusSqr) {
			return false;
		}
		float len = (float)Math.sqrt(sqrLen);
		return dx * dirx + dz * dirz > len * cosTheta;
	}
	
	// 优化的isPointInSector，减少sqrt开平方操作，原理一样
	public boolean isPointInSector2(float x, float z) {
		// 计算扇形和点的交叉有两步
		// 1 计算点到扇形所在圆圆心的距离，若大于扇形半径，则点肯定不在扇形内
		// 2 若点到圆心距离小于半径，则计算点到圆心的线段要在扇形两条边之间，p表示点，c表示扇形圆心，
		// 也就是p-c这个向量和扇形的方向向量的夹角a要小于等于扇形的theta, a <= theta, 因为cos是降调函数，所以cos(a) > cos(theta)
		// cos(a) = ((p - c) dot dir) / |p - c| > cos(theta)
		
		float dx = x - this.x;
		float dz = z - this.z;
		float sqrLen = dx * dx + dz * dz;
		if (sqrLen > radiusSqr) {
			return false;
		}
		// 减少开平方|p - c|
		float dot = dx * dirx + dz * dirz;
		if (dot >= 0 && cosTheta >= 0) {
			return dot * dot > sqrLen * cosTheta * cosTheta;
		}
		else if (dot < 0 && cosTheta < 0) {
			return dot * dot < sqrLen * cosTheta * cosTheta;
		}
		else {
			return dot >= 0;
		}
	}
}
